package se.webbzon.oschi01.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class Singletons {
	
	static final Map<Class<?extends Singleton>,Object> singletons = 
			new HashMap<Class<?extends Singleton>,Object>();
	
	@SuppressWarnings("unchecked")
	public static <C extends Singleton> C instance(Class<C> clazz) {
		C singleton = (C) singletons.get(clazz);
		if (singleton == null) try {
			Constructor<C> constructor = clazz.getDeclaredConstructor(new Class[0]);
	        constructor.setAccessible(true);
	        singleton = constructor.newInstance(new Object[0]);
			singletons.put(clazz, singleton);
		} catch (NoSuchMethodException e) {
			throw new IllegalArgumentException("The class " + clazz.getName() + " does not have any constructor with an empty argument list.", e);
		} catch (SecurityException e) {
			throw new IllegalArgumentException("The class " + clazz.getName() + " could not be instantiated as singleton due to unhandeled SecurityException.", e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException("The constructor of the class " + clazz.getName() + " is inaccessible.", e);
		} catch (InstantiationException e) {
			throw new IllegalArgumentException("The class " + clazz.getName() +" is abstract and can not be instantiated.", e);
		} catch (InvocationTargetException e) {
			throw new IllegalArgumentException("The constructor of the class " + clazz.getName() + " threw an exception during instantiation.", e);
		} 
		return singleton;
	}

}
